package com.ciaojian.store.controller.franchisees;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ciaojian.core.base.annotation.ApiIdempotent;
import com.ciaojian.core.mapper.StoreMapper;
import com.ciaojian.core.mapper.StorePayMapper;
import com.ciaojian.core.model.*;
import com.ciaojian.core.model.vo.StoreAmountVo;
import com.ciaojian.core.util.*;
import com.ciaojian.pay.core.enums.SignType;
import com.ciaojian.pay.wxpay.model.request.UnifiedOrderModel;
import com.ciaojian.pay.wxpay.model.response.NotifyResponse;
import com.ciaojian.pay.wxpay.model.response.UnifiedOrderModelResponse;
import com.ciaojian.pay.core.kit.WxPayKit;
import com.ciaojian.pay.wxpay.WxPayApi;
import com.ciaojian.pay.wxpay.model.response.UnifiedOrderModelResponse;
import com.ciaojian.store.pay.WxPayBeanFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

@Api(tags = "加盟商保证金接口")
@RestController
@RequestMapping("/franchisees/balance")
public class FStoreAmountController {
    @Resource
    private StorePayMapper storePayMapper;
    @Resource
    private StoreMapper storeMapper;

    @GetMapping("/getBalance")
    @ApiOperation("保证金余额")
    public Result getPayList(@RequestParam(required=true) @ApiParam("店铺") Integer storeId)  {
        Store store = storeMapper.selectById(storeId);
        if (ObjectUtil.isNull(store.getFranchiseesStoreAmount())){
            store.setFranchiseesStoreAmount(new BigDecimal(0));
        }
        BigDecimal franchiseesStoreAmount = store.getFranchiseesStoreAmount();
        StoreAmountVo storeAmountVo = new StoreAmountVo();
        storeAmountVo.setStoreAmount(franchiseesStoreAmount);

        BigDecimal bigDecimal5000 = new BigDecimal(5000);
        if (franchiseesStoreAmount.compareTo(bigDecimal5000) == -1){
            BigDecimal subtract = bigDecimal5000.subtract(franchiseesStoreAmount);
            storeAmountVo.setNeedAmount(subtract);
        }
        return Result.ok(storeAmountVo);
    }


    @GetMapping("/getPayList")
    @ApiOperation("充值保证金列表")
    public Result getPayList(@RequestParam(required=true) @ApiParam("店铺") Integer storeId,
                             @RequestParam(required=false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date beginDate,
                             @RequestParam(required=false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date endDate)  {

        QueryWrapper<StorePay> storePayQueryWrapper = new QueryWrapper<>();
        storePayQueryWrapper.eq("store_id",storeId);
        if (ObjectUtil.isNotNull(beginDate)&&ObjectUtil.isNotNull(endDate)) {
            storePayQueryWrapper.between("add_time", beginDate, endDate);
        }
        List<StorePay> storePays = storePayMapper.selectList(storePayQueryWrapper);
        return Result.ok(storePays);
    }


    @ApiIdempotent
    @Transactional
    @ApiOperation("保证金充值支付")
    @PostMapping("/pay")
    public synchronized Result storePay(HttpServletRequest request,
                                       @ApiParam("店铺") Integer storeId,
                                       @ApiParam("充值金额") BigDecimal money,
                                        String openid
    ) throws IllegalAccessException, JsonProcessingException {


//        String openid = TokenUtil.getUserOpenid(token);
        if (money.compareTo(new BigDecimal("0.01")) <= 0) {
            money = new BigDecimal("0.01");
        }


        String prefix = new SimpleDateFormat("yyyyMMddHHmmsss").format(new Date());
//        int i = (int) (Math.random() * 900) + 100;
//        String s = Integer.toString(i);

        //获取自增 最后三位
        SnowFlake snowFlake = new SnowFlake(0, 0);
        long nextId = snowFlake.nextId();
        String str = Long.toString(nextId);
        String s = str.substring(str.length() - 3);
        String orderNo = prefix.concat("U").concat(String.valueOf(storeId)).concat(s);
        Store store = storeMapper.selectById(storeId);

        if (store.getType()!=2){
            return Result.error("该店铺不是加盟店");
        }

        StorePay storePay = new StorePay();
        storePay.setStoreId(storeId);
        storePay.setStoreName(store.getTitle());
        storePay.setAddTime(new Date());
        storePay.setStatus(0);
        storePay.setOutTradeNo(orderNo);
        storePay.setGoodsAmount(money);
        storePay.insert();

        WxPayBase wxPayBean = WxPayBeanFactory.getInstance(store, 2);

        System.out.println(1);

        Map<String, Object> params = UnifiedOrderModel
                .builder()
                .appid(wxPayBean.getAppId())
                .mch_id(wxPayBean.getMchId())
                .nonce_str(RandomUtil.randomString(32))
                .body(store.getFranchiseesStoreName())
                .out_trade_no(orderNo)
                // 微信支付要求金额以分为单位,并且不能存在小数
                // 所以这里从元转成分,并且去掉小数位
                .total_fee(BigDecimalUtil.increase(money, BigDecimalUtil.HUNDRED, 0).toString())
                .spbill_create_ip(StringUtil.getIpAddr(request))
                .notify_url(wxPayBean.getDomain().concat("/store/franchisees/balance/wxNotify"))
                .trade_type(wxPayBean.getTradeType())
                .openid(openid)
                .build()
                .createSign(wxPayBean.getKey(), SignType.MD5);
        //组装参数，用户生成统一下单接口的签名
        LogUtil.writePayLog(">>>payMethod,请求参数:params={}>>>", params);
        // 返回 xml 格式表单
        String xmlResult = WxPayApi.pushOrder(params);
        UnifiedOrderModelResponse response = WxPayKit.xmlToBean(xmlResult, UnifiedOrderModelResponse.class);
        LogUtil.writePayLog(">>>payMethod,,支付请求返回参数={}>>>", response.toString());

        // 将二次签名构建的数据返回给前端并唤起小程序支付
        Map<String, Object> packageParams = new HashMap<>(7);

        // 请求失败
        WxPayKit.codeIsOk(response);
        // 微信支付返回的预支付id
        String prepayId = response.getPrepay_id();
        // 二次签名，构建公众号唤起支付的参数,这里的签名方式要与上面统一下单请求签名方式保持一致
        packageParams.putAll(WxPayKit.miniAppPrepayIdCreateSign(
                wxPayBean.getAppId(),
                prepayId,
                wxPayBean.getKey(),
                SignType.MD5));
        return Result.ok(packageParams);

    }

    @ApiOperation(value = "保证金支付回调", hidden = true)
    @Transactional(rollbackFor = Exception.class)
    @PostMapping(value = "/wxNotify")
    public void jianfaWxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // todo 建立一个回调队列,如果接口出现异常则把订单放进队列,再通过主动向微信请求订单信息来更新订单
        String notifyXml = getNotifyXml(request);
        NotifyResponse notifyResponse = WxPayKit.xmlToBean(notifyXml, NotifyResponse.class);
        LogUtil.writePayLog(">>>WxNotify notifyXml 信息>>>map={}", notifyResponse.toString());
        // 获取商户系统内部订单号（即取号时生成的订单编号)
        String orderNo = notifyResponse.getOut_trade_no();
        // 获取订单id
        QueryWrapper<StorePay> storePayQueryWrapper = new QueryWrapper<>();
        StorePay storePay = new StorePay().selectOne(storePayQueryWrapper);
        LogUtil.writePayLog(">>>WxNotify>>>订单号={}的订单id={}", orderNo, storePay.getId());
        LogUtil.writePayLog(">>>WxNotify>>>订单={}", storePay);


        if (ObjectUtil.isNotNull(storePay)) {
            // 微信支付金额,此时还是以分为单位,所以转成 元为单位
            BigDecimal totalFee = BigDecimalUtil.reduce(notifyResponse.getTotal_fee(), BigDecimalUtil.HUNDRED);


            Store store = new Store().selectById(storePay.getStoreId());

            storePay.setPayAmount(totalFee);
            BigDecimal totalAmount = storePay.getGoodsAmount().add(store.getFranchiseesStoreAmount());
            store.setFranchiseesStoreAmount(totalAmount);
            store.updateById();

            storePay.setPayTime(new Date());
            storePay.setStatus(1);
            storePay.setAfterAmount(totalAmount);
            storePay.updateById();


//                    BaseTemplate baseTemplate = BaseTemplate.builder(TemplateIdEnum.COMMENT_TO_EXPIRE)
//                            .touser(notifyResponse.getOpenid())
//                            .data(TakeCommentMessage.builder()
//                                    .thing1(order.getStoreName())
//                                    .time2(expiredTime)
//                                    .thing3("反馈评价可随机获取剪发券奖励!")
//                                    .build()
//                            );
//                    SubMessageSendResponse response1 = WxMiniAppApi.subscribeMessageSend(baseTemplate);
//                    if (response1.getErrcode() == 0) {
//
//                    } else {
//                        LogUtil.writeBusinessLog("提醒评价通知失败CommentExpired: {}", response1.getErrmsg());
//                    }

            // 通知微信回调成功
            notifyResponse.notifyWx(response);
            }
    }

    /**
     * 获取微信回调xml
     *
     * @param request request
     * @return xml回调信息
     */
    private String getNotifyXml(HttpServletRequest request) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String line;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
        // sb为微信返回的xml
        return sb.toString();
    }

}
